﻿/*
 *
 * The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); 
 * you may not use this file except in compliance with the License.
 * 
 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 * 
 * See the License for the specific language governing rights and limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Web;

namespace FBConnectAuth.Tests
{
	[TestFixture]
	public class FBConnectAuthenticationFixture
	{
		private const string apiKey = "a3e275abe037642238f94f00cy718f7f";
		private const string appSecret = "85d664fce118247b82ff97e3883594a4";
		
		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestConstructor_NullApiKey()
		{
			new FBConnectAuthentication(null, appSecret);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestConstructor_NullAppSecret()
		{
			new FBConnectAuthentication(apiKey, null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestConstructor_EmptyApiKey()
		{
			new FBConnectAuthentication("", appSecret);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void TestConstructor_EmptyAppSecret()
		{
			new FBConnectAuthentication(apiKey, "");
		}

		[Test]
		public void TestConstructor_ValidParams()
		{
			new FBConnectAuthentication(apiKey, appSecret);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestValidate_NullCookies()
		{
			var auth = new FBConnectAuthentication(apiKey, appSecret);
			auth.Validate(null);
		}

		[Test]
		public void TestValidate_ValidSignature()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey,appSecret);

			string signature = "d6eddc7644d9b8abf3d4c21da00a9647";
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			HttpCookieCollection cookies = CreateCookies(apiKey, signature, "1834825588", sessionSecret, sessionKey, 0, true);
			ValidationState expected = ValidationState.Valid;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected,actual,"Signature was expected to be valid.");

		}

		[Test]
		public void TestValidate_ValidSignature_CookiesInNonAlphaOrder()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);

			string signature = "d6eddc7644d9b8abf3d4c21da00a9647";
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			HttpCookieCollection cookies = CreateCookies(apiKey, signature, "1834825588", sessionSecret, sessionKey, 0, false);
			ValidationState expected = ValidationState.Valid;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected, actual, "Signature was expected to be valid.");

		}

		private static HttpCookieCollection CreateCookies(string apiKey, string signature, string uid, string sessionSecret, string sessionKey, int expires, bool inAlphabeticalOrder)
		{
			string prefix = apiKey + "_";
			HttpCookieCollection result;
			if (inAlphabeticalOrder)
			{
				result = new HttpCookieCollection
				             	{
				             		new HttpCookie(apiKey, signature),
				             		new HttpCookie(prefix + "expires", expires.ToString()),
				             		new HttpCookie(prefix + "session_key", sessionKey),
				             		new HttpCookie(prefix + "ss", sessionSecret),
				             		new HttpCookie(prefix + "user", uid),
				             	};
			}
			else
			{
				result = new HttpCookieCollection
				             	{
				             		new HttpCookie(apiKey, signature),
				             		new HttpCookie(prefix + "ss", sessionSecret),
				             		new HttpCookie(prefix + "user", uid),
				             		new HttpCookie(prefix + "session_key", sessionKey),
				             		new HttpCookie(prefix + "expires", expires.ToString()),
				             	};
			}
			result.Add(new HttpCookie("dsfgdfgdfgdfgfg", "dfgdfdfgdfg3345"));
			result.Add(new HttpCookie("AnotherRandomCookie", "RandomCookieValue"));
			result.Add(new HttpCookie(apiKey + "SuffixWithNoUnderscore", "this should be ignored"));

			return result;
		}

		[Test]
		public void TestValidate_ValidSignature_MixedCaseApiKey()
		{
			string apiKey = "a3e275aBE037642238f94f00CY718F7f";
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);

			string signature = "d6eddc7644d9b8abf3d4c21da00a9647";
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			HttpCookieCollection cookies = CreateCookies(apiKey.ToLowerInvariant(), signature, "1834825588", sessionSecret, sessionKey, 0, true);
			ValidationState expected = ValidationState.Valid;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected, actual, "Signature was expected to be valid.");
		}
		
		[Test]
		public void TestValidate_InvalidSignature_CookiesInAlphaOrder()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);

			string signature = "d6eddc7644d3b8abf3d4c21da00a9647"; //just a little different
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			HttpCookieCollection cookies = CreateCookies(apiKey, signature, "1834825588", sessionSecret, sessionKey, 0, true);
			ValidationState expected = ValidationState.InvalidSignature;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected, actual, "Signature was not expected to be valid.");
		}
		
		[Test]
		public void TestValidate_InvalidSignature_CookiesInNonAlphaOrder()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);

			string signature = "d6eddc7644d3b8abf3d4c21da00a9647"; //just a little different
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			HttpCookieCollection cookies = CreateCookies(apiKey, signature, "1834825588", sessionSecret, sessionKey, 0, false);
			ValidationState expected = ValidationState.InvalidSignature;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected, actual, "Signature was not expected to be valid.");
		}

		[Test]
		public void TestValidate_MissingSignature()
		{
			HttpCookieCollection cookies = CreateCookiesWithNoFBConnectInfo();

			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);
			ValidationState expected = ValidationState.NoSignatureFound;
			ValidationState actual = auth.Validate(cookies);

			Assert.AreEqual(expected, actual, "Signature was not included in cookie collection.");
		}

		private static HttpCookieCollection CreateCookiesWithNoFBConnectInfo()
		{
			return new HttpCookieCollection
			       	{
			       		new HttpCookie("dsfgdfgdfgdfgfg", "dfgdfdfgdfg3345"),
			       		new HttpCookie("AnotherRandomCookie", "RandomCookieValue"),
			       		new HttpCookie(apiKey + "SuffixWithNoUnderscore", "this should be ignored")
			       	};
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestGetSession_NullCookies()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);
			auth.GetSession(null);
		}

		[Test]
		public void TestGetSession_ValidSignature()
		{
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);
			string signature = "d6eddc7644d9b8abf3d4c21da00a9647";
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			string userId = "1834825588";

			HttpCookieCollection cookies = CreateCookies(apiKey, signature, userId, sessionSecret, sessionKey, 0, false);
			FBConnectSession session = auth.GetSession(cookies);
			
			Assert.IsNotNull(session,"Session was not expected to be null.");
			Assert.AreEqual(userId,session.UserID);
			Assert.AreEqual(sessionSecret, session.SessionSecret);
			Assert.AreEqual(sessionKey, session.SessionKey);
			Assert.AreEqual(0, session.Expires);
		}
		
		[Test]
		public void TestGetSession_InvalidSignature()
		{
			bool correctExceptionThrown = false;
			
			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);
			string signature = "d6eddc8533d9b8abf3d4c21da00a9647";
			string sessionSecret = "09e197e93648d7547bff3039629b679c";
			string sessionKey = "814414edd7ecd44e25ee1c9f-1834825588";
			string userId = "1834825588";

			HttpCookieCollection cookies = CreateCookies(apiKey, signature, userId, sessionSecret, sessionKey, 0, false);
			try
			{
				FBConnectSession session = auth.GetSession(cookies);
			}
			catch (FBConnectAuthenticationException ex)
			{
				if (ex.Reason == ValidationState.InvalidSignature) correctExceptionThrown = true;
			}

			Assert.IsTrue(correctExceptionThrown);
		}

		[Test]
		public void TestGetSession_MissingSignature()
		{
			bool correctExceptionThrown = false;

			FBConnectAuthentication auth = new FBConnectAuthentication(apiKey, appSecret);
			HttpCookieCollection cookies = CreateCookiesWithNoFBConnectInfo();
			try
			{
				FBConnectSession session = auth.GetSession(cookies);
			}
			catch (FBConnectAuthenticationException ex)
			{
				if (ex.Reason == ValidationState.NoSignatureFound) correctExceptionThrown = true;
			}
			Assert.IsTrue(correctExceptionThrown);
		}
	}
}
